﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using GoGrid;
using MSTestContrib.Specifications;
using GoGrid.Specifications.Properties;

namespace GoGrid.Specifications
{
    [TestClass]
    [SpecificationDescription("Connection initiates activities against the GoGrid API.")]
    public class ConnectionSpecification : GoGridSpecificationBase
    {
        [TestMethod]
        [ScenarioDescription("Connection ListImages returns a complete set of images from the GoGrid API.")]
        public void ConnectionListImagesReturnsACompleteSetOfImagesFromTheGoGridApi()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("a list of images is returned", x => x.State.Images = x.State.Connection.ListImages())
                .Then("there should be 97 images", x => x.State.Images.Count == 97);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListImages can support paging.")]
        public void ConnectionListImagesCanSupportPaging()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all images", x => x.State.AllImages = x.State.Connection.ListImages())
                .And("then get the first page of 5 images", x => x.State.FirstPageOfImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.Of(5, 0), DataCenter.Any))
                .And("then get the second page of 5 images", x => x.State.SecondPageOfImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.Of(5, 1), DataCenter.Any))
                .And("then get the second page of 5 images", x => x.State.LastPageOfImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.Of(5, 19), DataCenter.Any))
                .Then("the first page should have 5 images", x => x.State.FirstPageOfImages.Count == 5)
                .And("the first entry on the first page should match the first entry on the list of all images", x => x.State.FirstPageOfImages[0].Name == x.State.AllImages[0].Name)
                .And("the fifth entry on the first page should match the fifth entry on the list of all images", x => x.State.FirstPageOfImages[4].Name == x.State.AllImages[4].Name)
                .And("the second page should have 5 images", x => x.State.SecondPageOfImages.Count == 5)
                .And("the first entry on the second page should match the sixth entry on the list of all images", x => x.State.SecondPageOfImages[0].Name == x.State.AllImages[5].Name)
                .And("the fifth entry on the second page should match the tenth entry on the list of all images", x => x.State.SecondPageOfImages[4].Name == x.State.AllImages[9].Name)
                .And("the last page of images should have 2 images", x => x.State.LastPageOfImages.Count == 2)
                .And("the first entry on the last page should match the ninty fifth entry on the list of all images", x => x.State.LastPageOfImages[0].Name == x.State.AllImages[95].Name)
                .And("the third entry on the last page should match the ninth seventh entry on the list of all images", x => x.State.LastPageOfImages[1].Name == x.State.AllImages[96].Name);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListImages can support type selection.")]
        public void ConnectionListImagesCanSupportTypeSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all images", x => x.State.AllImages = x.State.Connection.ListImages())
                .And("then get a list of all web server images", x => x.State.WebServerImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.WebServer, ImageState.Any, Paging.None, DataCenter.Any))
                .And("then get a list of all database server images", x => x.State.DatabaseServerImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.DatabaseServer, ImageState.Any, Paging.None, DataCenter.Any))
                .Then("all images returned from the list of all web server images should be web server images", x => (x.State.WebServerImages as List<Image>).All(y => y.Type.Name == "Web Server"))
                .And("all images returned from the list of all database server images should be database server images", x => (x.State.DatabaseServerImages as List<Image>).All(y => y.Type.Name == "Database Server"))
                .And("the addition of web server images and database server images should add up to the total of all images", x => x.State.WebServerImages.Count + x.State.DatabaseServerImages.Count == x.State.AllImages.Count);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListImages can support state selection.")]
        public void ConnectionListImagesCanSupportStateSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all images", x => x.State.AllImages = x.State.Connection.ListImages())
                .And("then get a list of all images in an available state", x => x.State.AvailableImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Available, Paging.None, DataCenter.Any))
                .And("then get a list of all images in a saving state", x => x.State.SavingImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Saving, Paging.None, DataCenter.Any))
                .Then("the images returned from the list of all available images should be available images", x => (x.State.AvailableImages as List<Image>).All(y => y.State.Name == "Available"))
                .And("the images returned from the list of all saving images should be saving images", x => (x.State.SavingImages as List<Image>).All(y => y.State.Name == "Saving"))
                .And("the addition of available images and saving images should add up to the total of all images", x => x.State.AvailableImages.Count + x.State.SavingImages.Count == x.State.AllImages.Count);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListImages can support data center selection.")]
        public void ConnectionListImagesCanSupportDataCenterSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we get a list of all images in the west coast data center", x => x.State.WestCoastImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.None, DataCenter.USWest1))
                .And("we get a list of all images in the east coast data center", x => x.State.EastCoastImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.None, DataCenter.USEast1))
                .Then("the number of images should be different between the two locations", x => x.State.WestCoastImages.Count != x.State.EastCoastImages.Count);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListImages when queried for Available Web Server images should return a sub-set of all images.")]
        public void ConnectionListImagesWhenQueriedForAvailableWebServerImagesShouldReturnASubSetOfAllImages()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we get a list all images", x => x.State.AllImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.Any, ImageState.Any, Paging.None, DataCenter.Any))
                .And("we get a list of all images that are available and of type web server", x => x.State.AvailableWebServerImages = x.State.Connection.ListImages(ImageAccessibility.Any, ImageType.WebServer, ImageState.Available, Paging.None, DataCenter.Any))
                .Then("the exception (LINQ terminology) of both results should be greater than zero.", x => this.ComputeExceptBetweenAllImagesAndAvailableWebServerImages(x).Count != 0);
        }

        private List<Image> ComputeExceptBetweenAllImagesAndAvailableWebServerImages(SpecificationContext specificationContext)
        {
            var allImages = specificationContext.State.AllImages as List<Image>;
            var availableWebServerImages = specificationContext.State.AvailableWebServerImages as List<Image>;
            var exceptResult = allImages.Except(availableWebServerImages);
            return exceptResult.ToList();
        }

        [TestMethod]
        [ScenarioDescription("Connection ListIPAddresses returns a complete set of IP addresses from the GoGrid API.")]
        public void ConnectionListIPAddressesReturnsACompleteSetOfIPAddressesFromTheGoGridApi()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("a list of IP addresses is returned", x => x.State.AllAddresses = x.State.Connection.ListIPAddresses())
                .Then("there should be 544 addresses", x => x.State.AllAddresses.Count == 544);
        }
        [TestMethod]
        [ScenarioDescription("Connection ListIPAddresses can support paging.")]
        public void ConnectionListIPAddressesCanSupportPaging()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all addresses", x => x.State.AllAddresses = x.State.Connection.ListIPAddresses())
                .And("then get the first page of 5 addresses", x => x.State.FirstPageOfAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Any, Paging.Of(5, 0), DataCenter.Any))
                .And("then get the second page of 5 addresses", x => x.State.SecondPageOfAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Any, Paging.Of(5, 1), DataCenter.Any))
                .And("then get the second page of 5 addresses", x => x.State.LastPageOfAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Any, Paging.Of(5, 108), DataCenter.Any))
                .Then("the first page should have 5 addresses", x => x.State.FirstPageOfAddresses.Count == 5)
                .And("the first entry on the first page should match the first entry on the list of all addresses", x => x.State.FirstPageOfAddresses[0].Address == x.State.AllAddresses[0].Address)
                .And("the fifth entry on the first page should match the fifth entry on the list of all addresses", x => x.State.FirstPageOfAddresses[4].Address == x.State.AllAddresses[4].Address)
                .And("the second page should have 5 addresses", x => x.State.SecondPageOfAddresses.Count == 5)
                .And("the first entry on the second page should match the sixth entry on the list of all addresses", x => x.State.SecondPageOfAddresses[0].Address == x.State.AllAddresses[5].Address)
                .And("the fifth entry on the second page should match the tenth entry on the list of all addresses", x => x.State.SecondPageOfAddresses[4].Address == x.State.AllAddresses[9].Address)
                .And("the last page of images should have 5 addresses", x => x.State.LastPageOfAddresses.Count == 4)
                .And("the first entry on the last page should match the 540th on the list of all addresses", x => x.State.LastPageOfAddresses[0].Address == x.State.AllAddresses[540].Address)
                .And("the third entry on the last page should match the 543rd entry  on the list of all addresses", x => x.State.LastPageOfAddresses[3].Address == x.State.AllAddresses[543].Address);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListIPAddresses can support type selection.")]
        public void ConnectionListIPAddressesCanSupportTypeSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all addresses", x => x.State.AllIPAddresses = x.State.Connection.ListIPAddresses())
                .And("then get a list of all public addresses", x => x.State.PublicIPAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Public, Paging.None, DataCenter.Any))
                .And("then get a list of all private addresses", x => x.State.PrivateIPAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Private, Paging.None, DataCenter.Any))
                .Then("all addresses returned from the list of all public addresses should be public", x => (x.State.PublicIPAddresses as List<IPAddress>).All(y => y.IsPublic == true))
                .And("all addresses returned from the list of all private addresses should be private", x => (x.State.PrivateIPAddresses as List<IPAddress>).All(y => y.IsPublic == false))
                .And("the addition of the public addresses and the private addresses should add up to the total of all addresses", x => x.State.PublicIPAddresses.Count + x.State.PrivateIPAddresses.Count == x.State.AllIPAddresses.Count);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListIPAddresses can support state selection.")]
        [Ignore()]
        public void ConnectionListIPAddressesCanSupportStateSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all addresses", x => x.State.AllIPAddresses = x.State.Connection.ListIPAddresses())
                .And("then get a list of all assigned addresses", x => x.State.AssignedAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Assigned, IPAddressType.Any, Paging.None, DataCenter.Any))
                .And("then get a list of all unassigned addresses", x => x.State.UnassignedAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Unassigned, IPAddressType.Any, Paging.None, DataCenter.Any))
                .Then("all addresses returned from the list of all assigned addresses should be assigned", x => (x.State.AssignedAddresses as List<IPAddress>).All(y => y.State.Name == "Assigned"))
                .And("all addresses returned from the list of all private unassigned should be unassigned", x => (x.State.UnassignedAddresses as List<IPAddress>).All(y => y.State.Name == "Unassigned"))
                .And("the addition of the assigned addresses and the unassigned addresses should add up to the total of all addresses", x => x.State.AssignedAddresses.Count + x.State.UnassignedAddresses.Count == x.State.AllIPAddresses.Count);
        }

        [TestMethod]
        [ScenarioDescription("Connection ListIPAddresses can support data center selection.")]
        public void ConnectionListIPAddressesCanSupportDataCenterSelection()
        {
            Given("a valid GoGrid connection", x => x.State.Connection = GetConnection())
                .When("we first get a list of all addresses", x => x.State.AllIPAddresses = x.State.Connection.ListIPAddresses())
                .And("then get a list of all west coast addresses", x => x.State.WestCoastAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Any, Paging.None, DataCenter.USWest1))
                .And("then get a list of all east coast addresses", x => x.State.EastCoastAddresses = x.State.Connection.ListIPAddresses(IPAddressState.Any, IPAddressType.Any, Paging.None, DataCenter.USEast1))
                .Then("all addresses returned from the list of all west coast addresses should be in the west coast data center", x => (x.State.WestCoastAddresses as List<IPAddress>).All(y => y.DataCenter.Name == "US-West-1"))
                .And("all addresses returned from the list of all east coast addresses should be in the east coast data center", x => (x.State.EastCoastAddresses as List<IPAddress>).All(y => y.DataCenter.Name == "US-East-1"))
                .And("the addition of the west coast addresses and the east coast addresses should add up to the total of all addresses", x => x.State.WestCoastAddresses.Count + x.State.EastCoastAddresses.Count == x.State.AllIPAddresses.Count);
        }
    }
}
